#include <stdlib.h> 
#include <stdio.h> 
#include <conio.h>  // Windows library?


#define XDATA(arg) (arg +0) 
#define XCMD(arg) (arg +1)
#define YDATA(arg) (arg +2)
#define YCMD(arg) (arg +3)

// Reset and Load Signal Decoder Registers
#define RLD(arg) (arg | 0x08)
#define XRLD(arg) (arg | 0)
#define YRLD(arg) XRLD(arg)
#define Rst_BP 0x01 				// Reset Byte Pointer
#define Rst_CNTR 0x02 				// Reset Counter
#define Rst_FLAGS 0x04 				// Reset Flags
#define Rst_E 0x06 					// Reset Error?
#define Trf_PR_CNTR 0x08 			// Transfer Preset Register to Counter
#define Trf_CNTR_OL 0x10 			// Transfer Counter to Output Latch
#define Trf_PS0_PSC 0x18 			// Transfer ?

// Counter Mode Registers
#define CMR(arg) (arg | 0xA0)		// 
#define XCMR(arg) (arg | 0x20)		// X Counter Mode Register
#define YCMR(arg) XCMR(arg) 		// Y Counter Mode Register
#define BINCnt 0x00 				// Binary Count Mode
#define BCDCnt 0x01  				// BCD Count Mode
#define NrmCnt 0x00 				// Normal Count Mode
#define RngLmt 0x02 				// Range-limit Count Mode (upper and lower limit set) (freezes counter at CNTR=PR upper limit and CNTR=0 lower limit)
#define NRcyc 0x04  				// Non-Recycle Mode (see p.3)
#define ModN 0x06 					// Module-N Count Mode (see p.3)
#define NQDX 0x00 					// Non-Quadrature
#define QDX1 0x08 					// Quadrature x1
#define QDX2 0x10 					// Quadrature x2
#define QDX4 0x18 					// Quadrature x4

// Input-Output Control Registers
#define IOR(arg) (arg | 0xC0) 		// 
#define XIOR(arg) (arg | 0x40) 		//
#define YIOR(arg) XIOR(arg) 		//
#define DisAB 0x00 					//
#define EnAB 0x01 					//
#define LCNTR 0x00 					//
#define LOL 0x20 					//
#define RCNTR 0x00 					//
#define ABGate 0x04 				//
#define CYBW 0x00 					//
#define CPBW 0x08 					//
#define CB_UPDN 0x10 				//
#define IDX_ERR 0x18 				//

// Index Control Registers
#define IDR(arg) (arg | 0xE0)
#define XIDR(arg) (arg | 0x60)		// Select IDR
#define YIDR(arg) XIDR(arg)			// Select IDR
#define DisIDX 0x00					// Disable Index
#define EnIDX 0x01  				// Enable Index
#define NIDX 0x00 					// Negative Index Polarity
#define PIDX 0x02 					// Positive Index Polarity
#define LIDX 0x00 					// (LCNTR)/(LOL) Pin is Indexed
#define RIDX 0x04 					// (RCNTR)/(ABG) Pin is Indexed


/*
 * Init_7266
 *
 * Initialize 7266 as follows (X + Y CNTR)
 * Modulo N count mode for N = 0x123456
 * Binary Counting
 * Index on LCNTR/LOL Input
 * CY and BW outputs
 * RCNTR/ABG controls Counters
 * A and B Enabled
 */
void Init_7266(int Addr);
void Init_7266(int Addr)
{
	// Setup IOR Register
	outp(XCMD(Addr), IOR(DisAB + LOL + ABGate + CYBW)); // Disable Counters and Set CY BW Mode

	// Setup RLD Register
	outp(XCMD(Addr), RLD(Rst_BP + Rst_FLAGS)); // Reset Byte Pointer (BP) and Flags
	outp(XDATA(Addr), 0x06); // Load 6 to PR0 to setup Transfer of PS0
	outp(YDATA(Addr), 0x06); // Load 6 to PR0 to setup Transfer to PS0
	outp(XCMD(Addr), RLD(Rst_BP + Rst_CNTR)); // Reset BP and Reset Counter

	// Setup IDR Register
	outp(XCMD(Addr), IDR(EnIDX + NIDX + LIDX)); // Enable Negative Index on LCNTR/LOL Input

	// Setup CMR Register
	outp(XCMD(Addr), CMR(BINCnt + ModN + QDX4)); // Set Binary Mondulo N Quadrature x4

	// Setup PR Register for Modulo N Counter to 0x123456
	outp(XDATA(Addr), 0x56); // Least significant Byte first
	outp(XDATA(Addr), 0x34); // Then middle byte
	outp(XDATA(Addr), 0x12); // Then most significant byte

	// Setup PR Register for Modulo N Counter to 0x123456
	outp(YDATA(Addr), 0x56); // Least significant byte
	outp(YDATA(Addr), 0x34); // Then middle byte
	outp(YDATA(Addr), 0x12); // Then most significant byte
	
	// Enable Counters
	outp(XCMD(Addr), IOR(EnAB))

}


/*
 * Write_7266
 *
 * Input: Addr has Address of 7266 counter
 * Data: has 24 bit data to be written to PR register
 */
void Write_7266(int Addr, unsigned long Data);
void Write_7266(int Addr, unsigned long Data)
{
	outp(XCMD(Addr), RLD(Rst_BP)); // Reset Byte Pointer to Synchronize Byte Writing
	outp(XDATA(Addr), (unsigned char) Data);
	Data >>= 8;
	outp(XDATA(Addr), (unsigned char) Data);
	Data >>= 8;
	outp(XDATA(Addr), (unsigned char) Data);
}


/*
 * Read_7266_OL
 * 
 * Input: Addr has Address of 7266 counter
 * Ouput: Data returns 24 bit OL register value
 */
unsigned long Read_7266_OL(int Addr);
unsigned long Read_7266_OL(int Addr)
{
	unsigned long Data = 0;
	outp(XCMD(Addr), (RLD(Rst_BP + Trf_CNTR_OL))); // Reset Byte Pointer to Synchronize Byte reading and Transferring of data from counters to OL.
	Data |= (unsigned long) inp(XDATA(Addr)); // Read byte 0 from OL
	Irotr(Data, 8); // Rotate for next byte
	Data |= (unsigned long) inp(XDATA(Addr)); // Read byte 2 from OL
	Irotr(Data, 16);  // Rotate for last byte
	return(Data);
}


/*
 * Get_7266_Flags
 * 
 * Input: Addr has Address of 7266 counter
 * Returns: Flags of counter
 */
unsigned char Get_7266_Flags(int Addr);
unsigned char Get_7266_Flags(int Addr)
{
	return(inp(CMD(Addr)));
}




